package cn.zwy.实战;

import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.POP;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class ASMProxyMethodVisitor extends MethodVisitor {


    public ASMProxyMethodVisitor(MethodVisitor mv) {
        super(Opcodes.ASM6, mv);
    }

    @Override
    public void visitCode() {
        // 此方法在访问方法的头部时被访问到，仅被访问一次
        // visitMethodInsn(Opcodes.INVOKESTATIC,
        // Type.getInternalName(AOPAspect.class), "begin", "()V", false);

        // var map = new HashMap();
        mv.visitCode();
        mv.visitTypeInsn(NEW, "java/util/HashMap");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V", false);
        mv.visitVarInsn(ASTORE, 3);

        // map.put("key", value)
        for (int i = 0; i < ASMProxyClassVisitor.CUR_METHOD_PARAMETER_NAMES.get().size(); i++) {
            mv.visitVarInsn(ALOAD, 3);
            mv.visitLdcInsn(ASMProxyClassVisitor.CUR_METHOD_PARAMETER_NAMES.get().get(i));
            mv.visitVarInsn(ALOAD, i + 1);
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put",
                    "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true);
            mv.visitInsn(POP);
        }

        // mv.visitVarInsn(ALOAD, 3);
        // mv.visitLdcInsn("email");
        // mv.visitVarInsn(ALOAD, 2);
        // mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put",
        // "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true);
        // mv.visitInsn(POP);

        mv.visitVarInsn(ALOAD, 3);
        mv.visitMethodInsn(INVOKESTATIC, "cn/zwy/\u5b9e\u6218/AOPAspect", "before", "(Ljava/util/Map;)V", false);

        // mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
        // "Ljava/io/PrintStream;");
        // mv.visitLdcInsn("\u6dfb\u52a0\u7528\u6237");
        // mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
        // "(Ljava/lang/String;)V", false);

        // mv.visitInsn(RETURN);

        // mv.visitLocalVariable("this", "Lcn/zwy/\u5b9e\u6218/TOProxy;", null,
        // l0, l6, 0);
        // mv.visitLocalVariable("name", "Ljava/lang/String;", null, l0, l6, 1);
        // mv.visitLocalVariable("email", "Ljava/lang/String;", null, l0, l6,
        // 2);
        // mv.visitLocalVariable("params", "Ljava/util/Map;",
        // "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;", l1, l6, 3);
        // mv.visitMaxs(3, 4);
        // mv.visitEnd();
        super.visitCode();

    }

    @Override
    public void visitInsn(int opcode) {
        // 此方法可以获取方法中每一条指令的操作类型，被访问多次
        // 如应在方法结尾处添加新指令，则应判断：
        if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
            // visitMethodInsn(Opcodes.INVOKESTATIC,
            // Type.getInternalName(AOPAspect.class), "end", "()V", false);
            mv.visitVarInsn(ALOAD, 3);
            mv.visitMethodInsn(INVOKESTATIC, "cn/zwy/\u5b9e\u6218/AOPAspect", "after", "(Ljava/util/Map;)V", false);
        }
        super.visitInsn(opcode);
    }
}
